// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef CLOUDAPPENGINE_CAEAGENT_H
#define CLOUDAPPENGINE_CAEAGENT_H

#include <vector>
#include "../cae_common/CaeTimer.h"
#include "../cae_common/CaeConfigManage.h"
#include "../cae_dataPipe/CaeDataPipe.h"
#include "../cae_common/CaeDefine.h"
#include "../cae_socket/CaeTcpSocket.h"
#include "../cae_service/CaeEngineControl.h"
#include "../cae_common/CaeHttps.h"
#include "../cae_service/CaeSocketAgent.h"
#include "../cae_service/CaeTcpServerSocket.h"
#include "../cae_service/CaeClientService.h"
#include "../cae_service/CaeHttpsJobThread.h"
#include "../cae_service/CaeHeartbeatThread.h"
#include "../cae_service/CaeDataChannelServer.h"
#include "../cae_service/CaeImeControl.h"
#include "../cae_service/CaeConnectionAgent.h"

class CaeAgent {
public:
    CaeAgent();
    ~CaeAgent();

    static CaeAgent &GetInstance();
    CaeAgent(const CaeAgent &) = delete;
    CaeAgent &operator = (const CaeAgent &) = delete;

    CaeHttpsJobThread *m_caeHttpsJobThread;
    CaeHeartbeatThread *m_heartbeatThread;
    CaeEngineControl *m_engineControl;
    CaeHttps *m_caeHttps;
    vector<CaeDataPipe *> m_caePipes;

    CaeServerNotice *m_serverNotice;
    // tcp
    CaeTcpClientService *m_tcpClientService;
    CaeTcpServerSocket *m_tcpServerSocket;
    // tcp_tls
    CaeTcpTlsClientService *m_tlsClientService;
    CaeTcpServerSocket *m_tlsServerSocket;
    // ws
    CaeWebClientService *m_webClientService;
    CaeTcpServerSocket *m_webServerSocket;
    // wss
    CaeWSSClientService *m_wssClientService;
    CaeTcpServerSocket *m_wssServerSocket;

    CaeDataChannelServer *m_channelServer;

    int Init();

    void Boot();

    void Exit();

    static bool Start();

    static bool Stop();

    void Restart();

    void SetStatus(int status);

    int GetStatus() const;

    void LockStatus();

    void UnlockStatus();

    void CloseClient();

    void ClearPipesData() noexcept;

    void ClearScreenshotPipesData() noexcept;

    void OnNewClientConnectCallback(CaeSocket *socket);

    void InitPipes();

    bool CheckClearCmdCondition() const;

    CaeDataPipe* GetDataPipe(int type);

    CaeDataPipe* GetScreenshotDataPipe();

    bool IsIpInBlacklist(const string& ip);

    void AddIpToBlacklist(const string& ip);

    long GetLastRequestPublicKeyTimestamp() const;

    void SetLastRequestPublicKeyTimestamp(long lastRequestPublicKeyTimestamp);

    void StartCloudPhoneIme();

    int SendCustomDataToClient(const std::shared_ptr<uint8_t>& data, int size, uint8_t type);

    void AddVerifiedConnectionId(const string& ip, const string& port);

    void DeleteVerifiedConnectionId(const string& ip, const string& port);

    bool IsVerifiedIp(const string& ip);

protected:
    bool CreateServerSockets();

    void DestroyServerSockets() noexcept;

private:
    CaeTimerThread *m_timerThread;

    volatile int m_caeStatus;
    pthread_mutex_t m_statusLock;
    volatile bool m_doReset;
    volatile bool m_doRestart;

    bool m_isInit;
    std::mutex m_initLock;
    std::mutex m_whiteListLock;

    vector<string> m_ipBlackList;
    long m_lastRequestPublicKeyTimestamp = 0;

    unique_ptr<CaeConnectionAgent> m_connectionAgent = nullptr;

    CaeDataPipe * m_screenshotPipe;

    // key: ip, value: 相同ip的不同端口
    std::map<string, std::set<string>> m_ipWhiteList;
};

#endif // CLOUDAPPENGINE_CAEAGENT_H
